using System;
using System.Collections.Generic;
using System.Text;

namespace csammisrun.MsnLib.Utility
{
  public delegate void SyncCompleteHandler(Sync sync);

  [Flags]
  public enum ListOperationType
  {
    ForwardList = 0x01,
    AllowList = 0x02,
    BlockList = 0x04,
    ReverseList = 0x08
  }

  public class Sync
  {
    private Session _parent = null;
    private CommandProcessor _proc = null;
    private CommandRegistrar _registry = null;
    private CommandRegistrar _backup = null;
    private int _totalusers = 0;
    private int _receivedusers = 0;
    private int _totalgroups = 0;
    private int _receivedgroups = 0;

    public event SyncCompleteHandler SyncComplete;

    public Sync(Session parent, CommandProcessor processor)
    {
      _parent = parent;
      _proc = processor;

      // Build the local redirector
      CommandRegistrar cr = new CommandRegistrar();
      cr.RegisterHandlerForServerCommand("BLP", new CommandHandler(BlpCmd));
      cr.RegisterHandlerForServerCommand("PRP", new CommandHandler(PrpCmd));
      cr.RegisterHandlerForServerCommand("LSG", new CommandHandler(LsgCmd));
      cr.RegisterHandlerForServerCommand("LST", new CommandHandler(LstCmd));
      cr.RegisterHandlerForServerCommand("BPR", null);
      _registry = cr;
    }

    /// <summary>
    /// Suspends the command processor's normal registry while
    /// the synchronization is in process (until the specified numbers of users and groups have been read)
    /// </summary>
    public void BeginSync(int totalusers, int totalgroups)
    {
      lock (this)
      {
        // For the love of god, don't back up the registry twice
        if (_totalgroups != 0)
        {
          return;
        }

        _totalgroups = totalgroups;
        _totalusers = totalusers;
        _backup = _proc.Registry;
        _proc.Registry = _registry;
      }
    }

    /// <summary>
    /// Determine whether control should be set back to the Notification object
    /// </summary>
    private void CheckForCommandTransfer()
    {
      lock (this)
      {
        if (_receivedusers == _totalusers)
        {
          _proc.Registry = _backup;
          if (this.SyncComplete != null)
          {
            this.SyncComplete(this);
          }
        }
      }
    }

    #region Command handlers
    /// <summary>
    /// Gets the default visibility setting from the server
    /// </summary>
    private void BlpCmd(CommandProcessor processor, MsnCommand command)
    {
      UserListType listtype = UserList.GetListTypeByName(command.Parameters[0]);
      if (listtype == UserListType.Allow)
      {
        // Allow by default
        // Only users in the deny list will be blocked
      }
      else if (listtype == UserListType.Block)
      {
        // Block by default
        // Only users in the allow list will be let in
      }
    }

    private void PrpCmd(CommandProcessor processor, MsnCommand command)
    {
      // Set our own phone numbers?  Do I *look* like a tool?
      // Not to mention that the values I'm receiving on csammisrun@hotmail.com - MBE and WWE -
      // aren't handled by libgaim to begin with.
    }

    private void LsgCmd(CommandProcessor processor, MsnCommand command)
    {
      int groupid = Int32.Parse(command.Parameters[0]);
      string groupname = command.Parameters[1];

      Group newgroup = new Group(groupid, groupname);
      _parent.OnGroupItemReceived(newgroup);

      IncrementGroupCount();
      Logging.WriteString(String.Format("Processed group {0}", groupname));
      CheckForCommandTransfer();
    }

    private void LstCmd(CommandProcessor processor, MsnCommand command)
    {
      string passport = command.Parameters[0];
      string friendly = command.Parameters[1];
      ListOperationType ops = (ListOperationType)Int32.Parse(command.Parameters[2]);

      User user = new User(_parent.Userlist, passport, friendly);
      if ((ops & ListOperationType.ForwardList) != 0)
      {
        string[] groups = command.Parameters[3].Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
        foreach(string group in groups)
        {
          user.Groups.Add(_parent.Userlist.FindGroupByID(Int32.Parse(group)));
        }
      }
      _parent.OnUserItemReceived(user);

      IncrementUserCount();
      Logging.WriteString(String.Format("Processed user {0}", passport));
      CheckForCommandTransfer();
    }
    #endregion

    #region Utility methods
    /// <summary>
    /// Increments the group count in a monitor region
    /// </summary>
    private void IncrementGroupCount()
    {
      lock (this)
      {
        _receivedgroups++;
      }
    }

    /// <summary>
    /// Increments the user count in a monitor region
    /// </summary>
    private void IncrementUserCount()
    {
      lock (this)
      {
        _receivedusers++;
      }
    }
    #endregion
  }
}